package com.zhou.framework.quartz.controller;


import com.zhou.framework.quartz.common.QuartzExecuteTypeEnum;
import com.zhou.framework.quartz.dto.*;
import com.zhou.framework.util.PageUtil;
import com.zhou.framework.util.SessionUtil;
import com.zhou.util.*;
import com.zhou.framework.aop.anotation.LogOption;
import com.zhou.framework.aop.enums.LogLevel;
import com.zhou.framework.model.RS;
import com.zhou.framework.quartz.common.JobConfigCheck;
import com.zhou.framework.quartz.common.QuartzLogStatusEnum;
import com.zhou.framework.quartz.config.QuartzConfig;
import com.zhou.framework.quartz.dao.QuartzLog;
import com.zhou.framework.quartz.model.JobConfig;
import com.zhou.framework.quartz.service.QuartzLogService;
import com.zhou.framework.quartz.service.QuartzService;
import com.zhou.framework.util.ExceptionUtil;
import com.zhou.framework.dto.StringDto;
import com.zhou.framework.dto.StringsDto;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.quartz.CronExpression;
import org.quartz.Job;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.text.ParseException;
import java.util.*;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author lang.zhou
 * @since 2023-02-21
 */
@Slf4j
@RestController
@RequestMapping("/sys/quartz")
public class QuartzController {

    @Autowired
    private QuartzService quartzService;
    @Autowired
    private QuartzLogService quartzLogService;

    @GetMapping("/status")
    @ApiOperation("查询quartz服务状态")
    @LogOption(LogLevel.QUERY)
    public Object status(){
        return RS.data(getStatus());
    }

    public boolean getStatus(){
        boolean isStart = false;
        try{
            Scheduler scheduler = quartzService.getScheduler();
            isStart = scheduler.isStarted() && !scheduler.isShutdown();
        }catch (Exception e){
            log.error("",e);
        }
        return isStart;
    }

    @PostMapping("/listJob")
    @ApiOperation("定时任务列表")
    @LogOption(LogLevel.QUERY)
    public Object getPageList(@RequestBody QuartzQueryDto dto){
        PageUtil.offsetPage(dto);
        List<JobPageDto> list = quartzService.getPageList(dto);
        return PageUtil.result(dto,list);
    }

    @RequestMapping("/getLogPageList")
    @ApiOperation("定时任务执行历史列表")
    @LogOption(LogLevel.QUERY)
    public Object getLogPageList(@RequestBody QuartzLogQueryDto dto){
        PageUtil.offsetPage(dto);
        List<QuartzLog> list = quartzLogService.listLog(dto);
        return PageUtil.result(dto,list);
    }

    @DeleteMapping("/delete")
    @ApiOperation("删除定时任务")
    @LogOption(LogLevel.SYSTEM)
    public Object delete(@RequestBody StringsDto dto){
        for (String jobName : dto.getStr()) {
            try{
                JobConfig config = quartzService.getJobByJobName(jobName);
                quartzService.deleteJob(config);
            }catch (Exception e){
                log.error("",e);
                return RS.failed("删除失败");
            }
        }
        return RS.success();
    }
    @PostMapping("/pause")
    @ApiOperation("暂停定时任务")
    @LogOption(LogLevel.SYSTEM)
    public Object pauseJob(@RequestBody StringsDto dto){
        for (String jobName : dto.getStr()) {
            try{
                JobConfig config = quartzService.getJobByJobName(jobName);
                quartzService.pauseJob(config);
            }catch (Exception e){
                log.error("",e);
                return RS.failed("暂停失败");
            }
        }
        return RS.success();
    }
    @PostMapping("/start")
    @ApiOperation("启动定时任务")
    @LogOption(LogLevel.SYSTEM)
    public Object startJob(@RequestBody StringsDto dto){
        for (String jobName : dto.getStr()) {
            try{
                JobConfig config = quartzService.getJobByJobName(jobName);
                quartzService.startJob(config);
            }catch (Exception e){
                log.error("",e);
                return RS.failed("启动失败");
            }
        }
        return RS.success();
    }

    @PostMapping("/save")
    @ApiOperation("修改定时任务")
    @LogOption(LogLevel.SYSTEM)
    public Object add(@RequestBody QuartzSaveDto dto){
        if(!getStatus()){
            return RS.failed("定时任务服务已关闭，不能操作定时任务");
        }
        JobConfig config = JobConfigCheck.newJob(dto.getJobName());
        config.setCron(dto.getCronExpression());
        try {
            String clazz = dto.getJobClassName().trim();
            Class c = Class.forName(clazz);
            config.setClazz(c);
            if(Objects.equals(dto.getOperator(), 1)){
                log.info("创建定时任务...");
                quartzService.createJob(config);
            }else{
                log.info("修改定时任务...");
                quartzService.update(config);
            }

        } catch (SchedulerException e) {
            log.error("",e);
            return RS.failed("保存定时任务失败！");
        } catch (ClassNotFoundException e) {
            return RS.failed("执行的代码不存在！");
        } catch (RuntimeException e) {
            String s = e.getMessage();
            if(s.contains("CronExpression")){
                return RS.failed("表达式不正确！");
            }
            return RS.failed("保存失败！");
        }
        return RS.success();
    }

    @PostMapping("/execute")
    @ApiOperation("手动执行定时任务")
    @LogOption(LogLevel.QUARTZ)
    public Object execute(@RequestBody StringDto dto){
        String jobName = dto.getStr();
        Exception ee = null;
        QuartzLog lo = new QuartzLog();
        lo.setName(jobName);
        lo.setOrgId(SessionUtil.getCurrentOrgId());
        lo.setType(QuartzExecuteTypeEnum.HAND.getEnumValue());
        lo.setStartTime(new Date());
        //0-执行中 1-已完成
        lo.setStatus(QuartzLogStatusEnum.DONE.getEnumValue());
        try {
            quartzLogService.saveLog(lo);
            lo.setStatus(QuartzLogStatusEnum.ERROR.getEnumValue());
            JobConfig config = quartzService.getJobByJobName(jobName);
            Class clazz = config.getClazz();
            Job c = (Job) Class.forName(clazz.getName()).newInstance();
            c.execute(null);
            lo.setStatus(QuartzLogStatusEnum.DONE.getEnumValue());
        } catch (SchedulerException e) {
            ee = e;
            return RS.failed("获取定时任务失败");
        } catch (ClassNotFoundException e) {
            ee = e;
            return RS.failed("执行的代码不存在");
        } catch (InstantiationException | IllegalAccessException e) {
            ee = e;
            return RS.failed("无法实例化执行代码");
        } catch (Exception e){
            ee = e;
            return RS.failed("执行失败");
        }finally {
            lo.setEndTime(new Date());
            if(ee != null){
                log.error("",ee);
                lo.setLog(StringTool.substring(ExceptionUtil.getString(ee,"手动执行失败！"),0,2000));
            }
            quartzLogService.saveLog(lo);
        }

        return RS.success();
    }

    @GetMapping("/getLogErrorDetail")
    @ApiOperation("查询定时任务错误日志")
    @LogOption(LogLevel.QUERY)
    public Object getLogErrorDetail(@RequestParam Integer logId){
        return RS.data(quartzLogService.getById(logId));
    }

    @PostMapping("/startService")
    @ApiOperation("打开定时任务总服务")
    @LogOption(LogLevel.SYSTEM)
    public Object startService(){
        try {
            quartzService.resetTriggerStatus(QuartzConfig.tableFix);
            quartzService.updateQuartzLogError();
            quartzService.reLoad();
            return "ok";
        } catch (Exception e) {
            log.error("",e);
            return "打开定时任务服务时异常";
        }
    }

    @PostMapping("/stopService")
    @ApiOperation("关闭定时任务总服务")
    @LogOption(LogLevel.SYSTEM)
    public Object stopService(){
        try {
            quartzService.stop();
            return "ok";
        } catch (SchedulerException e) {
            log.error("",e);
            return "关闭定时任务服务时异常";
        }
    }
    @PostMapping("/getCronExpression")
    @ApiOperation("cron表达式解析")
    @LogOption(LogLevel.QUERY)
    public Object getCronExpression(@RequestBody RateDto dto){
        RS rs = RS.success();
        int minuteSpace = NumberUtil.safeToInteger(dto.getMinute(), 0);
        if(Objects.equals(dto.getType(),1)){
            StringBuilder expression = new StringBuilder();
            String[] templates = new String[]{"0", "0", "*", "*", "*", "?"};
            templates[1] = "0/" + minuteSpace;
            for (String template : templates) {
                expression.append(template).append(" ");
            }
            rs.set("time",expression.toString()).set("executeTimeList","每隔" + minuteSpace + "分钟执行一次");
        }else{
            String week = StringTool.join(dto.getWeek(),",");
            String hour = dto.getTime().split(":")[0];
            String minute = dto.getTime().split(":")[1];
            String[] template = new String[]{"0", "0", "0", "?", "*", "*"};

            //按照每周执行
            StringBuilder expression = new StringBuilder();
            if (!"".equals(week)) {
                template[1] = minute;
                template[2] = hour;
                template[5] = week ;
            } else {
                //按照每小时或每分钟   0 0/5 * * * ?    一天中在每个小时的20分钟执行一次 0 20 * * * ?
                if ("-1".equals(hour)) {
                    template[1] = "0/" + minute;
                    template[2] = "*";
                    template[3] = "*";
                    template[4] = "*";
                    template[5] = "?";
                } else {
                    template[1] = minute;
                    template[2] = hour;
                    template[3] = "*";
                    template[4] = "*";
                    template[5] = "?";
                }
            }
            for (String tem : template) {
                expression.append(tem).append(" ");
            }
            log.info(expression.toString());
            try {
                CronExpression exp = new CronExpression(expression.toString().trim());
                Date date = new Date();
                String str = "";
                for (int i = 1; i <= 10; i++) {
                    date = exp.getNextValidTimeAfter(date);
                    str += "".equals(str) ? TimeUtil.formatDate(date, "yyyy-MM-dd HH:mm:ss") : "<br/>" + TimeUtil.formatDate(date, "yyyy-MM-dd HH:mm:ss");
                    //将执行时间往后延一分钟，即可到下次执行时间
                    date = new Date(date.getTime() + 1000);
                }
                rs.set("executeTimeList", str);
            } catch (ParseException e) {
                rs.set("err", "配置错误");
            }
            rs.set("time", expression.toString().trim());
        }
        return rs;
    }

}

